#ifndef MCGPP_LOGGER_H
#define MCGPP_LOGGER_H

#include <iostream>
#include <iomanip>

namespace mcgpp {
  namespace meta {
    template<typename ... Pack>
    void expandPack(Pack &&...) {}
  }    // namespace meta
  class Logger {
  public:
    explicit Logger(const bool newline) :
            _newline(newline),
            _oss() {}

    template<typename Arg, typename ... Args>
    Logger(const bool newline, Arg &&arg, Args &&... args) :
            _newline(newline),
            _oss() {
      _oss << "[" << std::forward<Arg>(arg);
      meta::expandPack((_oss << ":" << std::forward<Args>(args)) ...);
      _oss << "]: ";
    }

    template<typename T>
    Logger &operator<<(const T &output) {
      _oss << output << ' ';
      return *this;
    }

    template<typename T>
    Logger &operator<<(const T *output) {
      _oss << output << ' ';
      return *this;
    }


    Logger &operator<<(decltype(std::left) &output) {
      _oss << output;
      return *this;
    }

    Logger &operator<<(const decltype(std::setw(1)) &output) {
      _oss << output;
      return *this;
    }

    ~Logger() {
      std::cout << _oss.str();
      if (_newline) {
        std::cout << std::endl;
      } else {
        std::cout << ' ';
      }
    }

  private:
    bool _newline;
    std::ostringstream _oss;
  };

  class LoggerVoidify {
  public:
    void operator&(Logger &) {}
  };
}
#endif //MCGPP_LOGGER_H
